package com.hcy.rabbitruntimeapi.websocket;

import com.hcy.rabbitruntimeapi.handler.MyAccessHandler;
import com.hcy.rabbitruntimeapi.handler.MyWebSocketFrameHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @Author huchenying
 * @Description
 * @Date 2021/12/15 13:19
 */
@Component
@Configuration
public class RuntimeCenterNettyWebsocket implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(RuntimeCenterNettyWebsocket.class);

    @Autowired
    MyAccessHandler myAccessHandler;
    @Autowired
    MyWebSocketFrameHandler myWebSocketFrameHandler;

    @Async
    public void run(ApplicationArguments args) {
        logger.info("开始启动websocket服务");
        EventLoopGroup boss = new NioEventLoopGroup(4);
        EventLoopGroup worker = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        // 因为基于Http协议 使用http编码和解码器
                        pipeline.addLast(new HttpServerCodec());
                        // 因为是以 块方式写，添加 ChunkedWriteHandler处理器
                        pipeline.addLast(new ChunkedWriteHandler());
                        /*
                            因为 http 在传输过程中是分段。 HttpObjectAggregator,就是可以将多个段聚合
                            这就是为什陌 当浏览器发送大量数据时救护发送多次http请求
                         **/
                        pipeline.addLast(new HttpObjectAggregator(8192));

                        // 对应websocket 数据是以帧 frame 的形式传输的
                        //可以看到WebsocketFrame 是有六个子类 多种形式 可以根据需要选取
                        //websocket的协议是这中形式 ws://localhost:20888/hello
                        //WebSocketServerProtocolHandler 的核心功能是将http协议升级成ws协议 保持长连接
                        // 自定义Handler 处理业务逻辑
                        pipeline.addLast("MyAccessHandler", myAccessHandler);
                        pipeline.addLast(new WebSocketServerProtocolHandler("/wss", null, true, 65536, false, true));
                        pipeline.addLast("MyHandler", myWebSocketFrameHandler);
                    }
                });

        try {
            ChannelFuture sync = bootstrap.bind("localhost", 20888).sync();
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
